package blackberry.util.field;

import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.TouchEvent;
import net.rim.device.api.ui.component.BitmapField;
import net.rim.device.api.ui.decor.BackgroundFactory;

public class DjControlBar extends Manager {
	
	public static final int VERTICAL_BAR = 0;
	public static final int HORIZONTAL_BAR = 1;
	
	private BitmapField handleField;;
	private Bitmap backgrounadBitmap;
			
	private DjControlBarChangeListener listener;
	
	private int numOfPiece;
	private int[] arrOfXorY;
	private int lastValueOfYorX;
	private int axis;
	
	private int currentIndex;
	private int YorXOfHandle;
	private int halfSizeOfHandle;
	
	private boolean touchDownInBounds;
	
	public DjControlBar(Bitmap handleBitmap, Bitmap backgroundBitmap, int numOfPiece,
			int initIndex, int axis) {
		super(0);
		
		this.handleField = new BitmapField(handleBitmap);
		add(handleField);
		
		this.axis = axis;
		this.backgrounadBitmap = backgroundBitmap;
		setBackground(BackgroundFactory.createBitmapBackground(backgroundBitmap));
		this.numOfPiece = numOfPiece;
		this.arrOfXorY = new int[numOfPiece];
		if (axis == AXIS_VERTICAL) {
			this.lastValueOfYorX = backgroundBitmap.getHeight() - handleBitmap.getHeight();
			halfSizeOfHandle = handleBitmap.getHeight() / 2;
		} else {
			this.lastValueOfYorX = backgroundBitmap.getWidth() - handleBitmap.getWidth();
			halfSizeOfHandle = handleBitmap.getWidth() / 2;
		}
	
		for (int i = 0; i < (numOfPiece - 1); i++) {
			arrOfXorY[i] = (lastValueOfYorX / (numOfPiece - 1)) * i;
		}
		arrOfXorY[numOfPiece - 1] = lastValueOfYorX;
		moveWithIndex(initIndex, false);
	}
	
	protected void sublayout(int width, int height) {
		
		setExtent(getPreferredWidth(), getPreferredHeight());
		
		if (axis == AXIS_VERTICAL ){
			
			setPositionChild(handleField, 
					0, 
					YorXOfHandle);
			
		} else {
			
			setPositionChild(handleField, 
					YorXOfHandle, 
					0);
		}
		
		layoutChild(handleField, 
				handleField.getPreferredWidth(),
				handleField.getPreferredHeight());
	}
	public int getPreferredWidth() {
		return backgrounadBitmap.getWidth();
	}
	public int getPreferredHeight() {
		return backgrounadBitmap.getHeight();
	}
	
	
	public void moveWithIndex(int index, boolean notify) {
		this.YorXOfHandle = arrOfXorY[index];
		setCurrentIndex(index);
		invalidate();
		sublayout(0, 0);
		if (notify)
			notifyControlBarListener(DjControlBarChangeListener.MOVE_WITH_INDEX);
	}
	
	
	public void moveUpward(){

		setCurrentIndex(getCurrentIndex() - 1);
		checkCurrentIndex();
		YorXOfHandle = arrOfXorY[getCurrentIndex()];
	
		invalidate();
		sublayout(0, 0);
		notifyControlBarListener(DjControlBarChangeListener.MOVE_UPWARD);

	}

	public void moveDownward(){

		setCurrentIndex(getCurrentIndex() + 1);
		checkCurrentIndex();
		YorXOfHandle = arrOfXorY[getCurrentIndex()];
	
		invalidate();
		sublayout(0, 0);
		notifyControlBarListener(DjControlBarChangeListener.MOVE_DOWNWARD);

	}
	private void checkCurrentIndex(){
		if (getCurrentIndex() < 0)
			setCurrentIndex(0);
		else if (getCurrentIndex() > numOfPiece - 1)
			setCurrentIndex(numOfPiece - 1);
	}
	
	
	public void notifyControlBarListener(int event){
		if (listener != null)
			listener.controlbarChanged(event, currentIndex);
	}
	public void setControlBarChangeListener(DjControlBarChangeListener listener) {
		this.listener = listener;
	}
	
	public int getCurrentIndex() {
		return currentIndex;
	}
	public void setCurrentIndex(int currentIndex) {
		this.currentIndex = currentIndex;
	}

	protected boolean touchEvent(TouchEvent message) {
		
		switch (message.getEvent()) {
		case TouchEvent.DOWN: {

			if (outOfBounds(message) || outOfHandleBounds(message))
				break;
			
			touchDownInBounds = true;
			if (axis == AXIS_VERTICAL) 
				YorXOfHandle = message.getY(1) - halfSizeOfHandle;
			else
				YorXOfHandle = message.getX(1) - halfSizeOfHandle;
			invalidate();
			sublayout(0, 0);
			break;
		}
		
		case TouchEvent.MOVE:{
			
			if (outOfHandleBounds(message))
				return true;
			
			if (touchDownInBounds) {
				
				if (axis == AXIS_VERTICAL)
					YorXOfHandle = message.getY(1) - halfSizeOfHandle;
				else
					YorXOfHandle = message.getX(1) - halfSizeOfHandle;
				invalidate();
				sublayout(0, 0);
			}
			
			return true;//쓸때 없는 스크롤 움직임을 막기위해
			
		}
		
		case TouchEvent.UP:{
			
			if (touchDownInBounds) { 

				touchDownInBounds = false;
				int minAbsolute = Integer.MAX_VALUE;
				int indexOfMinAbsolute = 0;
				if (axis == AXIS_VERTICAL) {
					
					for (int i = 0; i < arrOfXorY.length; i++) {
						if (minAbsolute > Math.abs(arrOfXorY[i] - (message.getY(1) - halfSizeOfHandle))) {
							minAbsolute = Math.abs(arrOfXorY[i] - (message.getY(1) - halfSizeOfHandle));
							indexOfMinAbsolute = i;
						}
					}
					
				} else {
					
					for (int i = 0; i < arrOfXorY.length; i++) {
						if (minAbsolute > Math.abs(arrOfXorY[i] - (message.getX(1) - halfSizeOfHandle))) {
							minAbsolute = Math.abs(arrOfXorY[i] - (message.getX(1) - halfSizeOfHandle));
							indexOfMinAbsolute = i;
						}
					}
					
				}
				setCurrentIndex(indexOfMinAbsolute);
				moveWithIndex(getCurrentIndex(), true);
				
			}
			
			break;
		}
		}

		return super.touchEvent(message);
	}
	private boolean outOfBounds(TouchEvent message){
		return message.getX(1) < 0 || message.getX(1) > getPreferredWidth() 
				|| message.getY(1) < 0 || message.getY(1)  > getPreferredHeight(); 
	}
	private boolean outOfHandleBounds(TouchEvent message){
		
		if (axis == AXIS_VERTICAL) {
			
			if (message.getY(1) < halfSizeOfHandle 
					|| message.getY(1) > arrOfXorY[numOfPiece - 1] + halfSizeOfHandle)
				return true;
			
		} else {
			
			if  (message.getX(1) < halfSizeOfHandle 
					|| message.getX(1) > arrOfXorY[numOfPiece - 1] + halfSizeOfHandle)
				return true;
				
		}
		
		return false;
	}
}